package dao

import (
	"context"
	"wxpay/internal/model"
	"wxpay/pkg/merrors"
	"wxpay/pkg/util"

	"github.com/nsqio/go-nsq"
	"github.com/patrickmn/go-cache"
	"gorm.io/gorm"
)

type Trade interface {
	// 创建交易
	Create(ctx context.Context, tx *gorm.DB, m *model.Trade) error
	// 查询交易
	QueryByOutTradeNo(ctx context.Context, db *gorm.DB, outTradeNo string) (t *model.Trade, err error)
	// 更新PrepayID
	UpdatePrepayIDInTx(ctx context.Context, tx *gorm.DB, t *model.Trade) (err error)
	// 更新payment
	UpdateVoucher(ctx context.Context, tx *gorm.DB, t *model.Trade) (err error)
	// 关闭trade
	Close(ctx context.Context, tx *gorm.DB, t *model.Trade) (err error)
}

type TradeRepo struct {
	*gorm.DB
	producer *nsq.Producer
	cache    *cache.Cache
}

func NewTradeRepo(d *gorm.DB, p *nsq.Producer, c *cache.Cache) *TradeRepo {
	return &TradeRepo{
		DB:       d,
		producer: p,
		cache:    c,
	}
}

// 创建交易
func (r *TradeRepo) Create(_ context.Context, tx *gorm.DB, m *model.Trade) error {
	const op merrors.Op = "TradeRepo.Create"
	if e := tx.Create(m).Error; e != nil {
		return merrors.E(op, merrors.DBError, e, merrors.ErrInternal)
	}
	return nil

}

func (r *TradeRepo) QueryByOutTradeNo(_ context.Context, db *gorm.DB, outTradeNo string) (t *model.Trade, err error) {
	const op merrors.Op = "TradeRepo.QueryByOutTradeNo"
	res := model.Trade{}
	if err := db.Model(&model.Trade{}).Where("out_trade_no = ?", outTradeNo).First(&res).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, merrors.E(op, merrors.NotExist, merrors.ErrNotFound, err)
		} else {
			return nil, err
		}
	}
	t = &res
	return
}

func (r *TradeRepo) UpdatePrepayIDInTx(_ context.Context, tx *gorm.DB, t *model.Trade) (err error) {
	const op merrors.Op = "TradeRepo.UpdatePrepayID"
	if e := tx.Model(t).Updates(map[string]interface{}{"prepay_id": t.PrepayID, "update_time": t.UpdateTime}).Error; e != nil {
		err = merrors.E(op, merrors.DBError, e, merrors.ErrInternal)
	}
	return
}

func (r *TradeRepo) UpdateVoucher(_ context.Context, tx *gorm.DB, t *model.Trade) (err error) {
	const op merrors.Op = "TradeRepo.UpdateVoucher"
	if e := tx.Model(t).Updates(map[string]interface{}{
		"wx_trans_id":      t.WxTransID,
		"trade_type":       t.TradeType,
		"trade_state":      t.TradeState,
		"trade_state_desc": t.TradeStateDesc,
		"success_time":     t.SuccessTime,
		"update_time":      t.UpdateTime,
		"extra":            t.Extra,
	}).Where("id = ?", t.ID).Error; e != nil {
		return merrors.E(op, merrors.DBError, e, merrors.ErrInternal)
	}
	return nil
}

func (r *TradeRepo) Close(_ context.Context, tx *gorm.DB, t *model.Trade) (err error) {
	const op merrors.Op = "TradeRepo.Close"
	if e := tx.Model(t).Updates(map[string]interface{}{"trade_state": t.TradeState, "trade_state_desc": t.TradeStateDesc, "update_time": util.GetNow()}).Error; e != nil {
		err = merrors.E(op, merrors.DBError, e, merrors.ErrInternal)
	}
	return
}
